#include <iostream>
#include <string>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<queue>

using namespace std;

// 定义互斥锁，用户线程间互斥
mutex mtx;
// 定义条件变量，用于线程间的同步通信
condition_variable cv;

// 最常见的问题就是消费者线程消费的更快，生产者线程还没生产出来就开始消费了
class Queue
{
    public:
    void put(int val)
    {
        // lock_guard<mutex> lock(mtx);

        unique_lock<mutex> lck(mtx);
        while(!que.empty())
        {
            // que不为空，生产者应该通知消费者去消费，消费完了在生产
            // 生产者进程应该进入阻塞状态，并把mtx互斥锁
            cv.wait(lck);
        }
        que.push(val);
        /*
        notify_one：通知另外的一个线程
        notify_all：通知另外的所有线程
        */
        // 通知其他的所有线程，生产了一个物品，可以进行消费了，
        // 其他线程得到该通知就会从 等待状态 -> 阻塞状态 -> 获取互斥锁才能继续执行。
        cv.notify_all(); 
        cout << "生产者 生产：" << val << "号物品" << endl;
    }
    int get()
    {
        // lock_guard<mutex> lock(mtx);
        unique_lock<mutex> lck(mtx);
        while(que.empty())
        {
            // 消费者发现que是空的，通知生产者线程生产物品
            // 进入等待状态，把互斥锁mutex进行释放
            cv.wait(lck);
        }
        int val = que.front();
        que.pop();
        cv.notify_all(); //消费完了，通知其他线程进行生产
        cout << "消费者 消费：" << val << "号物品" << endl;
        return val;
    }
    private:
        queue<int> que;
};
void producer(Queue* que)
{
    for (int i = 0; i <= 10;i++)
    {
        que->put(i);
        this_thread::sleep_for(chrono::milliseconds(100));
    }
}
void consumer(Queue* que)
{
    for (int i = 0; i <= 10; i++)
    {
        que->get();
        this_thread::sleep_for(chrono::milliseconds(100));
    }
}
int main()
{
    Queue que;
    thread t1(producer, &que);
    thread t2(consumer,&que);

    t1.join();
    t2.join();

    return 0;
}